package com.jfcloud.mall.order.aspect;

import java.io.IOException;
import java.io.Writer;
import java.lang.reflect.Method;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.alibaba.fastjson.JSON;
import com.jfcloud.common.annotation.CheckToken;
import com.jfcloud.common.aspect.BaseAspect;
import com.jfcloud.common.aspect.TokenUser;
import com.jfcloud.common.http.RespData;
import com.jfcloud.common.utils.MapUtil;
import com.jfcloud.common.utils.StringUtil;
import com.jfcloud.mall.order.rpc.feign.UserServiceClient;

@Aspect
@Component
public class TokenAspect extends BaseAspect{
	
	private static final Logger logger = LoggerFactory.getLogger(TokenAspect.class);
	
	@Autowired
	private UserServiceClient userService;
	
	@Around("@annotation(com.jfcloud.common.annotation.CheckToken)")
    public Object  aroundMethod(ProceedingJoinPoint point ) {
		logger.info("token aspect start");
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); 
		MethodSignature ms=(MethodSignature) point.getSignature();
		Method method=ms.getMethod();
		CheckToken check = method.getAnnotation(CheckToken.class);
		if(check!=null){
			Object[] args = point.getArgs();
			//解析参数
			Map<String,Object> argMap = analysisArgs(args,method);
			//判断访问类型
			String requestMethod = request.getMethod();
			String token =null;
			if("get".equalsIgnoreCase(requestMethod)){
				//get请求直接从request获取token
				token = request.getParameter("token");
			}else if("post".equalsIgnoreCase(requestMethod)){
				//post请求从requestBody里获取对象
				Object o = argMap.get(requestBody);
				if(o instanceof Map){
					Map p = (Map)o;
					if(StringUtil.isNotEmpty(p.get("token"))){
						token = p.get("token").toString();
					}else{
						logger.error("参数中必须要有 token");
						return null;
					}
				}else{
					//通过反射获取token
					try {
						Method getToken = o.getClass().getDeclaredMethod("getToken");
						if(getToken==null){
							logger.error(o.getClass().getName()+"必须有 getToken 方法");
							return null;
						}
						token = (String) getToken.invoke(o);
					} catch (Exception e) {
						logger.error(e.getMessage(),e);
						return null;
					}
				}
			}
			if(null == token || "".equals(token.trim())){
				try {
					writeErrorJson((HttpServletResponse) argMap.get(response),"token不能为空", 2);
				} catch (IOException e) {
					logger.error(e.getMessage(),e);
				}
				logger.info("token aspect fail :" + token);
				return null;
			}
			// 校验token
			RespData ru = userService.validateAndGet(token);
			if(null == ru || RespData.Success!=ru.getStatus()){
				try {
					writeErrorJson((HttpServletResponse) argMap.get(response),"token验证失败" , 2);
				} catch (IOException e) {
					logger.error(e.getMessage(),e);
				}
				logger.info("token aspect fail :" + token);
				return null;
			}else{//token 验证成功
				Map<String,Object> ruMap = (Map<String, Object>) ru.getDatas();
				Long userId = MapUtil.getLong("id", ruMap);
				String userName = MapUtil.getString("username", ruMap);
				
				TokenUser user = new TokenUser();
				user.setUserId(userId);
				user.setUserName(userName);
				
				request.setAttribute("tokenUser", user);
			}
		}
		Object retVal;
		try {
			retVal = point.proceed();
			return retVal;
		} catch (Throwable e) {
			logger.error(e.getMessage(),e);
		}  
		return null;
    }
	
	private void writeErrorJson(HttpServletResponse response, String errorMsg , int status) throws IOException{
		response.setContentType("application/json; charset=utf-8");
		response.setCharacterEncoding("utf-8");
		Writer writer = response.getWriter();
		RespData resp = new RespData(status,errorMsg);
		writer.write(JSON.toJSONString(resp));
		writer.flush();
		writer.close();
	}
	
}